﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace CSharpNewFeaturesUse
{
    /// <summary>
    /// 分两个部分，Range 和 Index
    /// </summary>
    public class RangeAndIndex
    {
        private class MyRange
        {
            private readonly MyIndex startIndex;
            private readonly MyIndex endIndex;
            public MyRange(MyIndex startIndex, MyIndex endIndex)
            {
                this.startIndex = startIndex;
                this.endIndex = endIndex;
            }
            public (int, int) convert(uint length)
            {
                int start = startIndex.convert(length);
                int end = endIndex.convert(length);
                if (start > end) throw new IndexOutOfRangeException();
                return (start, end - start);
            }
        }
        private class MyIndex
        {
            private readonly bool direction;
            private readonly uint index;
            public MyIndex(uint i, bool d = true)
            {
                index = i;
                direction = d;
            }
            public int convert(uint length)
            {
                if (index > length) throw new IndexOutOfRangeException();
                return direction ? (int)index : (int)(length - index);
            }
            // 由于 ^ 一元符号不可重载，将 ^ 符号换为 ~
            public static MyIndex operator ~(MyIndex i) => new MyIndex(i.index, !i.direction);
            public static implicit operator MyIndex(int i)
            {
                if (i < 0) throw new IndexOutOfRangeException();
                return new MyIndex((uint)i);
            }
            // 由于 ~ 二元符号不可重载，将 ~ 符号换为 -
            public static MyRange operator -(MyIndex i, MyIndex j) => new MyRange(i, j);
        }
        private class MyArray<T>
        {
            private T[] array;
            public MyArray(T[] array)
            {
                this.array = array;
            }
            public T this[MyIndex index]
            {
                get => array[index.convert((uint)array.Length)];
                set => array[index.convert((uint)array.Length)] = value;
            }
            public MyArray<T> this[MyRange range]
            {
                get
                {
                    Span<T> values = new Span<T>(array);
                    (int start, int length) = range.convert((uint)array.Length);
                    Span<T> result = values.Slice(start, length);
                    return new MyArray<T>(result.ToArray());
                }
            }
            public T[] convert() => array;
        }
        
        public static void ShowUse()
        {
            int[] ary = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            MyArray<int> myArray = new MyArray<int>(ary);

            // 展示Index
            Console.WriteLine("展示Index的实现");
            MyIndex mi1 = 3;
            MyIndex mi2 = ~(MyIndex)4;

            Index i1 = 3;  // 下标为 3
            Index i2 = ^4; // 倒数第 4 个元素
            Console.WriteLine($"expected: 第3个元素: {ary[i1]}, 倒数第4个元素{ary[i2]}"); // "3, 6"
            Console.WriteLine($"actual: 第3个元素: {myArray[mi1]}, 倒数第4个元素{myArray[mi2]}"); // "3, 6"

            // 展示切片
            Console.WriteLine("展示Range的实现");
            int[] slice = ary[i1..i2];
            MyArray<int> mySlice = myArray[mi1-mi2];

            Console.WriteLine($"expected: {string.Join(',', slice)}");
            Console.WriteLine($"actual: {string.Join(',', mySlice.convert())}");

            // 展示浅复制
            Console.WriteLine("展示浅复制");
            int[][] arr1 = { new int[] { 1 }, new int[] { 2 }, new int[] { 3 } };
            int[][] arr2 = { new int[] { 1 }, new int[] { 2 }, new int[] { 3 } };
            MyArray<int[]> myArr1 = new MyArray<int[]>(arr2);

            int[][] b = arr1[0..^1];
            MyArray<int[]> b1 = myArr1[0-~(MyIndex)1];

            b[1][0] = 222; //会改变arr1[1]的内容
            b1[1][0] = 222;

            Console.WriteLine($"expected: {arr1[1][0]}");
            Console.WriteLine($"actual: {myArr1[1][0]}");
        }
    }
}